/**
 * @author ahammer
 * @date 2009
 */

/*
 * This file is part of Iqm.
 * Copyright (c) 2010-2011 Helmut Ahammer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package op;
/**
 * @date   2009 03
 * @update 2009 12 "bandcombine" instead of "bandselect" for extracting single channel = no brightness problem
 */

import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.ParameterBlock;

import javax.media.jai.JAI;
import javax.media.jai.LookupTableJAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import javax.media.jai.TiledImage;
import tools.IqmColorConvert;
import main.IqmTools;

/**
 * This is the main image processing class
 * There exist two approaches:
 * A user defined JAI operator is just called 
 * or:
 * The actual processing is implemented in this class 
 */
public class IqmConvertOperator{
	

  public IqmConvertOperator() {
	  //WARNING: Don't declare fields here
	  //Fields declared here aren't thread safe! 
  }
  /**
   * 
   * @param ParametrBlockJAI pb 
   */
  public Object run (ParameterBlockJAI arg){
	  
	PlanarImage pi = (PlanarImage) arg.getSource(0);
	String imgName = (String) pi.getProperty("image_name");
    int opt8bit    = arg.getIntParameter("Options8bit");
    int opt16bit   = arg.getIntParameter("Options16bit");
    int optPalette = arg.getIntParameter("OptionsPalette");
    int optRGB     = arg.getIntParameter("OptionsRGB");
    //int numBands  = pi.getData().getNumBands();
	//int pixelSize = pi.getColorModel().getPixelSize();
	//String type = IqmTools.getImgTyp(pixelSize, numBands);
	String type = IqmTools.getImgTyp(pi);
	
	if (type.equals("8 bit")){  //convert 8 bit Image
	
		if (opt8bit == 0){  //8bit to RGB
//			PlanarImage[] pis = new PlanarImage[3];
//			pis[0] = ti;
//			pis[1] = ti;
//			pis[2] = ti;
			ParameterBlockJAI pb = new ParameterBlockJAI("bandmerge");
			for(int n = 0; n < 3; n++){
				pb.setSource(pi, n);
			}
			pi = JAI.create("bandmerge", pb, null);		
		}
		if (opt8bit == 1){  //8bit to 16bit
			ParameterBlock pb = new ParameterBlock();
			pb.addSource(pi);
		    pb.add(DataBuffer.TYPE_USHORT);  
		    pi = JAI.create("format",  pb);
		    
		    
//		    pb.removeSources();
//			pb.removeParameters();
//		    pb.addSource(pi);
//			RenderedOp extrema = JAI.create("extrema", pb);
//		    // Must get the extrema of all bands !
//		    double[] minVec = (double[])extrema.getProperty("minimum");
//		    double[] maxVec = (double[])extrema.getProperty("maximum");
//		    double min = minVec[0];
//		    double max = maxVec[0];
	
		    pb.removeSources();
			pb.removeParameters();
		    pb.addSource(pi);
		    pb.add(new double[] {65535.0/255.0}); //Rescale 
		    pb.add(new double[] {0.0}); //offset
			pi = JAI.create("rescale", pb);

		}
	}
	if (type.equals("16 bit")){  //convert 16bit Image

		if (opt16bit == 0){  //16bit to 8bit
			ParameterBlock pb = new ParameterBlock();
			pb.addSource(pi);
			RenderedOp extrema = JAI.create("extrema", pb);
		    // Must get the extrema of all bands !
		    double[] minVec = (double[])extrema.getProperty("minimum");
		    double[] maxVec = (double[])extrema.getProperty("maximum");
		    double min = minVec[0];
		    double max = maxVec[0];
	
			pb.removeSources();
			pb.removeParameters();
			pb.addSource(pi);
		    pb.add(new double[] {(255.0/max)}); //Rescale 
		    pb.add(new double[] {0.0}); //offset
			pi = JAI.create("rescale", pb);

			pb.removeSources();
			pb.removeParameters();
		    pb.addSource(pi);			
		    pb.add(DataBuffer.TYPE_BYTE);  
		    pi = JAI.create("format",  pb);

		}
		if (opt16bit == 1){  //gibt es noch nicht

		}			
	}
	if (type.equals("Palette")){  //convert Palette

	if (optPalette == 0){  //Palette to RGB
		    IndexColorModel icm = (IndexColorModel)pi.getColorModel();
		    byte[][] data = new byte[3][icm.getMapSize()];
		    icm.getReds(data[0]);
		    icm.getGreens(data[1]);
		    icm.getBlues(data[2]);
		    LookupTableJAI lut = new LookupTableJAI(data);
		    pi = JAI.create("lookup", pi, lut);  //RGB image
		}
		if (optPalette == 1){  //gibt es noch nicht

		}			
	}
	
	if (type.equals("RGB")){  //convert RGB Image

		if (optRGB == 0){  //NTSC
			double[][] m = {{ 0.114, 0.587, 0.299, 0 }};
			ParameterBlock pb = new ParameterBlock();
			pb.addSource(pi);
			pb.add(m);
			pi = JAI.create("bandcombine", pb, null);		
		}
		if (optRGB == 1){  //RGB Mean
			double[][] m = {{ 1./3, 1./3, 1./3, 0 }};
			ParameterBlock pb = new ParameterBlock();
			pb.addSource(pi);
			pb.add(m);
			pi = JAI.create("bandcombine", pb, null);
		}
		if (optRGB == 2){  //extract R
			//pi = JAI.create("bandselect", pi, new int[] {0});  //zu hell in der Darstellung!!!
		    double[][] matrix = { { 1.0d, 0.0d, 0.0d, 0.0d } };   
		    pi = JAI.create( "bandcombine", new ParameterBlock().addSource(pi).add(matrix), null);	
			pi.setProperty("image_name", imgName+"_Band1");
		}
		if (optRGB == 3){  //extract G		
			//pi = JAI.create("bandselect", pi, new int[] {1});
		    double[][] matrix = { { 0.0d, 1.0d, 0.0d, 0.0d } };   
		    pi = JAI.create( "bandcombine", new ParameterBlock().addSource(pi).add(matrix), null);	
			pi.setProperty("image_name", imgName+"_Band2");			
		}
		if (optRGB == 4){  //extract B
			//pi = JAI.create("bandselect", pi, new int[] {2});
		    double[][] matrix = { { 0.0d, 0.0d, 1.0d, 0.0d } };   
		    pi = JAI.create( "bandcombine", new ParameterBlock().addSource(pi).add(matrix), null);	
			pi.setProperty("image_name", imgName+"_Band3");
		}
		if (optRGB == 5){  //RGB to HSV   	    	
    		Raster raster = pi.getData();		   	          		
       		TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.rgb2hsb(raster));
       		pi = ti;	
    	}
		if (optRGB == 6){  //RGB to HLS
	   		Raster raster = pi.getData();		   	         		
        	TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.RGBtoHLS(raster));
       		pi = ti;	
		}
		if (optRGB == 7){  //RGB to CIELAB
	   		Raster raster = pi.getData();		   	         		
        	TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.RGBtoCIELAB(raster));
       		pi = ti;	
		}
		if (optRGB == 8){  //RGB to CIELUV
	   		Raster raster = pi.getData();		   	         		
        	TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.RGBtoCIELUV(raster));
       		pi = ti;	
		}
		if (optRGB == 9){  //RGB to CIEXYZ
	   		Raster raster = pi.getData();		   	         		
        	TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.RGBtoCIEXYZ(raster));
       		pi = ti;	
		}
			
		if (optRGB == 10){  //HSV to RGB
	   		Raster raster = pi.getData();		   	         		
       		TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.HSVtoRGB(raster));
       		pi = ti;
		
		}
		if (optRGB == 11){  //HLS to RGB
	   		Raster raster = pi.getData();		   	         		
       		TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.HLStoRGB(raster));
       		pi = ti;		
		}
		if (optRGB == 12){  //CIELAB to RGB
	   		Raster raster = pi.getData();		   	         		
       		TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.CIELABtoRGB(raster));
       		pi = ti;		
		}
		if (optRGB == 13){  //CIELUV to RGB
	   		Raster raster = pi.getData();		   	         		
       		TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.CIELUVtoRGB(raster));
       		pi = ti;		
		}
		if (optRGB == 14){  //CIEXYZ to RGB
	   		Raster raster = pi.getData();		   	         		
       		TiledImage ti = new TiledImage(pi, false);  //true ersetzt pi!!!
       		ti.setData(IqmColorConvert.CIEXYZtoRGB(raster));
       		pi = ti;		
		}	
	}	
	return pi;
  }
}//END
